using System.Collections.Generic;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Libs;

namespace Gameplay.PVE.TurnBase
{
    public class RenderComponent : IComponent,ITransmit
    {
        //渲染
        
        private BattleUnit unit;
        private GameObject renderer;
        private Animator animator;
        private string m_action;
        private bool needPlayDead = false;
        private string m_currentFrameAction = string.Empty;
        private SkinnedMeshRenderer[] meshRender;
        private bool needShowShadow;//残影
        private List<GhostShadow> shadowList;
        private float shadowInterval = 0.02f;
        private float lastShadowTime;

        private List<Material> flashMat = new List<Material>();
        private List<Material> iceMat = new List<Material>();

        //private List<MaterialPropertyBlock> flashMPB = new List<MaterialPropertyBlock>();
        //private List<SkinnedMeshRenderer> renderers = new List<SkinnedMeshRenderer>();
        
        private static readonly int FlashAmount = Shader.PropertyToID("_FlashAmount");
        private static readonly int MaskAmount = Shader.PropertyToID("_MaskAmount");
        private static readonly int MaskColor = Shader.PropertyToID("_MaskColor");
        private float flashDuration = 0.2f;
        private float flashStartTime = 0;
        private float lastFlashAmount = 0;

        private float animatorFrozenStartTime = 0;
        private float animatorFrozenDuration = 0.2f;
        private bool isAnimatorFrozen = false;
        private float cachedAnimatorSpeed;
        private bool isStun = false;
        
        
        private List<Vector4> colorList = new List<Vector4>();



        private struct GhostShadow
        {
            public GameObject gameObject;
            public float endTime;
        }
        
        void IClass.OnReset()
        {
            isAnimatorFrozen = false;
            flashMat.Clear();
            animator = null;
            PveResourceManager.RecoverResource(renderer,PveResourceManager.EPveResType.Model,unit.Data.modelId);
            renderer = null;
            m_action = string.Empty;
            m_currentFrameAction = string.Empty;

        }

        void IComponent.OnInitialize(BattleUnit unit)
        {
            this.unit = unit;
        }

        void IComponent.OnUpdate()
        {
            if (needShowShadow)
            {
                if (TimeManager.logicTime - lastShadowTime >= shadowInterval)
                {
                    CreateShadow();
                    lastShadowTime = TimeManager.logicTime;
                }
            }

            CheckShadowLifeTime();
            
            if (flashStartTime != 0)
            {
                float percent = (TimeManager.logicTime - flashStartTime) / flashDuration;
                if (percent <= 1)
                {
                    SetFlashAmount(lastFlashAmount * (1 - percent));
                }
                else
                {
                    flashStartTime = 0;
                    SetFlashAmount(0);
                }
            }

            
            if (animatorFrozenDuration != -1 && animatorFrozenStartTime + animatorFrozenDuration > TimeManager.logicTime)
            {
                animatorFrozenStartTime = 0;
                isAnimatorFrozen = false;
                SetAnimSpeed(cachedAnimatorSpeed);
            }
            
        }

        private void CreateShadow()
        {
            for (int i = 0; i < meshRender.Length; i++) 
            {
                Mesh mesh = new Mesh ();
                meshRender[i].BakeMesh(mesh);
            
                GameObject go = new GameObject();
                //go.hideFlags = HideFlags.HideAndDontSave;//面板不显示

                MeshFilter filter = go.AddComponent<MeshFilter>();
                filter.mesh = mesh;
            
                MeshRenderer meshRen = go.AddComponent<MeshRenderer>();
            
                meshRen.material = meshRender[i].material;
                //meshRen.material.shader = ghostShader;//设置xray效果
                //meshRen.material.SetFloat("_Intension", Intension);//颜色强度传入shader中*/
            
                go.transform.localScale = meshRender[i].transform.localScale;
                go.transform.position = meshRender[i].transform.position;
                go.transform.rotation = meshRender[i].transform.rotation;
            
                //item.meshRenderer = meshRen;
                shadowList.Add(new GhostShadow
                {
                    gameObject = go,
                    endTime = TimeManager.logicTime + 0.2f,
                });
            }
        }

        private void CheckShadowLifeTime()
        {
            for (int i = 0; i < shadowList.Count; i++)
            {
                if (TimeManager.logicTime > shadowList[i].endTime)
                {
                    GameObject.DestroyImmediate(shadowList[i].gameObject);
                    shadowList.RemoveAt(i);
                    i--;
                }
            }
        }

        public void ReceiveModel(GameObject model)
        {
            renderer = model;
        }
        
        void IComponent.OnBirth()
        {
            float modelScale = 1;
            if (renderer == null)
            {
                renderer = PveResourceManager.GetResource(PveResourceManager.EPveResType.Model, unit.Data.modelId);
            }
            
            renderer.transform.localScale = modelScale * new Vector3(PveUtils.globalRatio,PveUtils.globalRatio,PveUtils.globalRatio);
            renderer.transform.SetParent(unit.gameObject.transform);
            renderer.transform.localPosition = Vector3.zero;
            renderer.transform.localEulerAngles = Vector3.zero;
            animator = renderer.GetComponentInChildren<Animator>();
            if (animator != null)
            {
                animator.enabled = true;
            }

            meshRender = renderer.GetComponentsInChildren<SkinnedMeshRenderer>();
            
            shadowList = new List<GhostShadow>();

            for (int i = 0; i < meshRender.Length; i++)
            {
                var mats = meshRender[i].materials;
                for (int j = 0; j < mats.Length; j++)
                {
                    var mat = mats[j];
                    if (mat.shader.name.Contains("Flash"))
                    {
                        //renderers.Add(meshRender[i]);
                        flashMat.Add(mat);
                    }
                    else if (mat.shader.name.Contains("Frozen"))
                    {
                        iceMat.Add(mat);
                    }
                }
            }

            SetFlashAmount(0);
        }

        void IComponent.OnDead()
        {
            Play("Dead");
            SetFlashAmount(0);
            SetMaskAmount(0);
        }

        void ITransmit.OnTransmit(ETransmitType type, BaseTransmitArg arg)
        {
            if (type == ETransmitType.ShowHit)
            {
                if (animator == null)
                {
                    return;
                }
                lastFlashAmount = 0.7f;
                SetFlashAmount(lastFlashAmount);
                flashStartTime = TimeManager.logicTime;
                flashDuration = 0.4f;

                /*if (animatorFrozenDuration != -1 && animator.speed != 0)
                {
                    animatorFrozenDuration = 0.2f;
                    animatorFrozenStartTime = TimeManager.logicTime;
                    cachedAnimatorSpeed = animator.speed;
                    animator.speed = 0;
                    isAnimatorFrozen = true;
                }*/
                unit.Play("Hit");
            }
            else if (type == ETransmitType.AddColor)
            {
                var changeColorArg = arg as ChangeColorArg;
                colorList.Add(new Vector4(changeColorArg.rgb.x,changeColorArg.rgb.y,changeColorArg.rgb.z,changeColorArg.amount));
                RefreshColor();
            }
            else if (type == ETransmitType.RemoveColor)
            {
                var changeColorArg = arg as ChangeColorArg;
                for (int i = 0; i < colorList.Count; i++)
                {
                    var color = colorList[i];
                    if (color.x == changeColorArg.rgb.x && color.y == changeColorArg.rgb.y &&
                        color.z == changeColorArg.rgb.z && color.w == changeColorArg.amount)
                    {
                        colorList.RemoveAt(i);
                        break;
                    }
                }
                RefreshColor();
            }
            else if (type == ETransmitType.AddControl)
            {
                var controlArg = arg as ControlArg;
                //unit.Data.controlList.Add(controlArg.controlType);
                //unit.Data.controlList.Sort();
                RefreshControlState();
            }
            else if (type == ETransmitType.RemoveControl)
            {
                var controlArg = arg as ControlArg;
                //unit.Data.controlList.Remove(controlArg.controlType);
                //unit.Data.controlList.Sort();
                RefreshControlState();
            }
        }

        private void RefreshColor()
        {
            for (int i = colorList.Count - 1; i >= 0; i--)
            {
                var color = colorList[i];
                SetMaskColor(new Vector4(color.x,color.y,color.z,1));
                SetMaskAmount(color.w);
                return;
            }
            //没有颜色
            SetMaskAmount(0);
        }
        
        private void SetFlashAmount(float amount)
        {
            for (int i = 0; i < flashMat.Count; i++)
            {
                flashMat[i].SetFloat(FlashAmount,amount);
            }
        }

        private void SetMaskAmount(float amount)
        {
            for (int i = 0; i < flashMat.Count; i++)
            {
                flashMat[i].SetFloat(MaskAmount,amount);
            }
        }

        private void SetMaskColor(Vector4 color)
        {
            for (int i = 0; i < flashMat.Count; i++)
            {
                flashMat[i].SetVector(MaskColor,color);
            }
        }

        private void SetIce(float thickness)
        {
            for (int i = 0; i < iceMat.Count; i++)
            {
                iceMat[i].SetFloat(OutlineFactor,thickness);
            }
        }

        private void RefreshControlState()
        {
            if (animator == null)
            {
                return;
            }
            if (unit.Data.controlList.Count > 0)
            {
                int controlType = unit.Data.controlList[0];
                if (controlType == 1) //冻结
                {
                    animatorFrozenDuration = -1;
                    if (animator.speed != 0)
                    {
                        cachedAnimatorSpeed = animator.speed;
                    }

                    animator.speed = 0;
                    isAnimatorFrozen = true;
                    SetIce(0.045f);
                }
                else if (controlType == 2) // 麻痹
                {
                    animator.SetBool("IsStun",true);
                    isStun = true;
                    Play("Stun");
                }
                else
                {
                    SetIce(0);
                    animator.SetBool("IsStun",false);
                    isStun = false;
                    Play("Idle");
                }
            }
            else//没有被控制
            {
                animatorFrozenDuration = 0f;
                animatorFrozenStartTime = 0;
                isAnimatorFrozen = false;
                if (cachedAnimatorSpeed != 0)
                {
                    SetAnimSpeed(cachedAnimatorSpeed);
                }
                SetIce(0);
                animator.SetBool("IsStun",false);
                isStun = false;
                Play("Idle");
            }
        }
        
        

        public void Play(string action)
        {
            if (isStun && action == "Idle")
            {
                action = "Stun";
            }
            if (m_currentFrameAction == action && action != "Hit")
            {
                return;
            }

            if (m_action == "Cele" && action == "Idle")
            {
                return;
            }
            if (unit.Data.isDead && action != "Dead")
            {
                return;
            }


            int currentPriority;
            actionPriority.TryGetValue(m_currentFrameAction, out currentPriority);

            int priority;
            actionPriority.TryGetValue(action, out priority);

            if (priority == 0)
            {
                priority = 3;
            }
            if (currentPriority >= priority)
            {
                return;
            }
            //Debug.LogError(action);
            m_currentFrameAction = action;
            //Debug.LogError(unit.Data.id +"  " + m_currentFrameAction);
        }

        public void SetAnimSpeed(float speed)
        {
            if (animator == null)
            {
                return;
            }

            if (isAnimatorFrozen && speed != 0)
            {
                cachedAnimatorSpeed = speed;
                return;
            }
            animator.speed = speed;
        }

        private Dictionary<string,int> actionPriority = new Dictionary<string, int>
        {
            ["Dead"] = 5,
            ["Hit"] = 4,
            ["Cheer"] = 3,
            ["Skill"] = 3,
            ["Attack"] = 3,
            ["Cele"] = 3,
            ["MoveTo"] = 3,
            ["MoveBack"] = 3,
            ["MoveToAttack"] = 3,
            ["Attack_MoveTo"] = 3,
            ["Attack_MoveBack"] = 3,
            ["Attack_MoveToAttack"] = 3,
            ["Skill_MoveTo"] = 3,
            ["Skill_MoveBack"] = 3,
            ["Skill_MoveToAttack"] = 3,
            ["Run"] = 2,
            ["Walk2"] = 2,
            ["Walk"] = 2,
            ["Stun"] = 1,
            ["Idle"] = 1,
            [string.Empty] = 0,
        };

        private static readonly int OutlineFactor = Shader.PropertyToID("_OutlineFactor");


        public void BeforeUpdate()
        {
            //m_currentFrameAction = string.Empty;
        }

        public void LateUpdate()
        {
            if (m_currentFrameAction != string.Empty)
            {
                if (animator == null)
                {
                    return;
                }

                if (unit.Data.isDead && m_currentFrameAction != "Dead")
                {
                    return;
                }
                if (m_action != m_currentFrameAction || m_currentFrameAction == "Hit")
                {
                    animator.ResetTrigger(m_action);
                    animator.SetTrigger(m_currentFrameAction);
                    m_action = m_currentFrameAction;
                    //Debug.LogError("frame " + unit.Data.id + "  " + m_currentFrameAction);
                }
            }
            m_currentFrameAction = string.Empty;
        }
    }
}